home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / pc / files / t_unix / j109lxa4.tar / domhdr.c < prev    next >
C/C++ Source or Header  |  1994-06-04  |  12KB  |  501 lines

  1. /* Domain header conversion routines
  2.  * Copyright 1991 Phil Karn, KA9Q
  3.  *
  4.  * Additional support for the Domain Name Server
  5.  * by Johan. K. Reinalda, WG7J,
  6.  * based on previous work by Gerard v.d. Grinten, PA0GRI
  7.  */
  8. #include "global.h"
  9. #include "config.h"
  10. #include "mbuf.h"
  11. #include "domain.h"
  12.  
  13. static int dn_expand __ARGS((char *msg,char *eom,char *compressed,char *full,
  14.     int fullen));
  15. static char *getq __ARGS((struct rr **rrpp,char *msg,char *cp));
  16. static char *ntohrr __ARGS((struct rr **rrpp,char *msg,char *cp));
  17. static char *dn_compress __ARGS((char *cp,char *name));
  18. static char *htonrr __ARGS((struct rr *rr,char *buffer));
  19.  
  20. int
  21. ntohdomain(dhdr,bpp)
  22. register struct dhdr *dhdr;
  23. struct mbuf **bpp;
  24. {
  25.     int16 tmp,len;
  26.     register int16 i;
  27.     char *msg,*cp;
  28.     struct rr **rrpp;
  29.  
  30.     len = len_p(*bpp);
  31.     msg = mallocw((unsigned)len);
  32.     pullup(bpp,msg,len);
  33.     memset((char *)dhdr,0,sizeof(*dhdr));
  34.  
  35.     dhdr->id = get16(&msg[0]);
  36.     tmp = get16(&msg[2]);
  37.     if(tmp & 0x8000)
  38.         dhdr->qr = 1;
  39.     dhdr->opcode = (tmp >> 11) & 0xf;
  40.     if(tmp & 0x0400)
  41.         dhdr->aa = 1;
  42.     if(tmp & 0x0200)
  43.         dhdr->tc = 1;
  44.     if(tmp & 0x0100)
  45.         dhdr->rd = 1;
  46.     if(tmp & 0x0080)
  47.         dhdr->ra = 1;
  48.     dhdr->rcode = tmp & 0xf;
  49.     dhdr->qdcount = get16(&msg[4]);
  50.     dhdr->ancount = get16(&msg[6]);
  51.     dhdr->nscount = get16(&msg[8]);
  52.     dhdr->arcount = get16(&msg[10]);
  53.  
  54.     /* Now parse the variable length sections */
  55.     cp = &msg[12];
  56.  
  57.     /* Question section */
  58.     rrpp = &dhdr->questions;
  59.     for(i=0;i<dhdr->qdcount;i++){
  60.         if((cp = getq(rrpp,msg,cp)) == NULLCHAR){
  61.             free(msg);
  62.             return -1;
  63.         }
  64.         (*rrpp)->source = RR_QUESTION;
  65.         rrpp = &(*rrpp)->next;
  66.     }
  67.     *rrpp = NULLRR;
  68.  
  69.     /* Answer section */
  70.     rrpp = &dhdr->answers;
  71.     for(i=0;i<dhdr->ancount;i++){
  72.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  73.             free(msg);
  74.             return -1;
  75.         }
  76.         (*rrpp)->source = RR_ANSWER;
  77.         rrpp = &(*rrpp)->next;
  78.     }
  79.     *rrpp = NULLRR;
  80.  
  81.     /* Name server (authority) section */
  82.     rrpp = &dhdr->authority;
  83.     for(i=0;i<dhdr->nscount;i++){
  84.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  85.             free(msg);
  86.             return -1;
  87.         }
  88.         (*rrpp)->source = RR_AUTHORITY;
  89.         rrpp = &(*rrpp)->next;
  90.     }
  91.     *rrpp = NULLRR;
  92.  
  93.     /* Additional section */
  94.     rrpp = &dhdr->additional;
  95.     for(i=0;i<dhdr->arcount;i++){
  96.         if((cp = ntohrr(rrpp,msg,cp)) == NULLCHAR){
  97.             free(msg);
  98.             return -1;
  99.         }
  100.         (*rrpp)->source = RR_ADDITIONAL;
  101.         rrpp = &(*rrpp)->next;
  102.     }
  103.     *rrpp = NULLRR;
  104.     free(msg);
  105.     return 0;
  106. }
  107. static char *
  108. getq(rrpp,msg,cp)
  109. struct rr **rrpp;
  110. char *msg;
  111. char *cp;
  112. {
  113.     register struct rr *rrp;
  114.     int len;
  115.     char *name;
  116.  
  117.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  118.     name = mallocw(512);
  119.     len = dn_expand(msg,NULLCHAR,cp,name,512);
  120.     if(len == -1){
  121.         free(name);
  122.         return NULLCHAR;
  123.     }
  124.     cp += len;
  125.     rrp->name = strdup(name);
  126.     rrp->type = get16(cp);
  127.     cp += 2;
  128.     rrp->class = get16(cp);
  129.     cp += 2;
  130.     rrp->ttl = 0;
  131.     rrp->rdlength = 0;
  132.     free(name);
  133.     return cp;
  134. }
  135. /* Read a resource record from a domain message into a host structure */
  136. static char *
  137. ntohrr(rrpp,msg,cp)
  138. struct rr **rrpp; /* Where to allocate resource record structure */
  139. char *msg;      /* Pointer to beginning of domain message */
  140. char *cp;       /* Pointer to start of encoded RR record */
  141. {
  142.     register struct rr *rrp;
  143.     int len;
  144.     char *name;
  145.  
  146.     *rrpp = rrp = (struct rr *)callocw(1,sizeof(struct rr));
  147.     name = mallocw(512);
  148.     if((len = dn_expand(msg,NULLCHAR,cp,name,512)) == -1){
  149.         free(name);
  150.         return NULLCHAR;
  151.     }
  152.     cp += len;
  153.     rrp->name = strdup(name);
  154.     rrp->type = get16(cp);
  155.     cp += 2;
  156.     rrp->class = get16(cp);
  157.     cp+= 2;
  158.     rrp->ttl = get32(cp);
  159.     cp += 4;
  160.     rrp->rdlength = get16(cp);
  161.     cp += 2;
  162.     switch(rrp->type){
  163.     case TYPE_A:
  164.         /* Just read the address directly into the structure */
  165.         rrp->rdata.addr = get32(cp);
  166.         cp += 4;
  167.         break;
  168.     case TYPE_CNAME:
  169.     case TYPE_MB:
  170.     case TYPE_MG:
  171.     case TYPE_MR:
  172.     case TYPE_NS:
  173.     case TYPE_PTR:
  174.         /* These types all consist of a single domain name;
  175.          * convert it to ascii format
  176.          */
  177.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  178.         if(len == -1){
  179.             free(name);
  180.             return NULLCHAR;
  181.         }
  182.         rrp->rdata.name = strdup(name);
  183.         rrp->rdlength = strlen(name);
  184.         cp += len;
  185.         break;
  186.     case TYPE_HINFO:
  187.         len = *cp++;
  188.         rrp->rdata.hinfo.cpu = mallocw((unsigned)len+1);
  189.         memcpy( rrp->rdata.hinfo.cpu, cp, (size_t)len );
  190.         rrp->rdata.hinfo.cpu[len] = '\0';
  191.         cp += len;
  192.  
  193.         len = *cp++;
  194.         rrp->rdata.hinfo.os = mallocw((unsigned)len+1);
  195.         memcpy( rrp->rdata.hinfo.os, cp, (size_t)len );
  196.         rrp->rdata.hinfo.os[len] = '\0';
  197.         cp += len;
  198.         break;
  199.     case TYPE_MX:
  200.         rrp->rdata.mx.pref = get16(cp);
  201.         cp += 2;
  202.         /* Get domain name of exchanger */
  203.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  204.         if(len == -1){
  205.             free(name);
  206.             return NULLCHAR;
  207.         }
  208.         rrp->rdata.mx.exch = strdup(name);
  209.         cp += len;
  210.         break;
  211.     case TYPE_SOA:
  212.         /* Get domain name of name server */
  213.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  214.         if(len == -1){
  215.             free(name);
  216.             return NULLCHAR;
  217.         }
  218.         rrp->rdata.soa.mname = strdup(name);
  219.         cp += len;
  220.  
  221.         /* Get domain name of responsible person */
  222.         len = dn_expand(msg,NULLCHAR,cp,name,512);
  223.         if(len == -1){
  224.             free(name);
  225.             return NULLCHAR;
  226.         }
  227.         rrp->rdata.soa.rname = strdup(name);
  228.         cp += len;
  229.  
  230.         rrp->rdata.soa.serial = get32(cp);
  231.         cp += 4;
  232.         rrp->rdata.soa.refresh = get32(cp);
  233.         cp += 4;
  234.         rrp->rdata.soa.retry = get32(cp);
  235.         cp += 4;
  236.         rrp->rdata.soa.expire = get32(cp);
  237.         cp += 4;
  238.         rrp->rdata.soa.minimum = get32(cp);
  239.         cp += 4;
  240.         break;
  241.     case TYPE_TXT:
  242.         /* Just stash */
  243.         rrp->rdata.data = mallocw((unsigned)rrp->rdlength);
  244.         memcpy(rrp->rdata.data,cp,(size_t)rrp->rdlength);
  245.         cp += rrp->rdlength;
  246.         break;
  247.     default:
  248.         /* Ignore */
  249.         cp += rrp->rdlength;
  250.         break;
  251.     }
  252.     free(name);
  253.     return cp;
  254. }
  255.  
  256. /* Convert a compressed domain name to the human-readable form */
  257. static int
  258. dn_expand(msg,eom,compressed,full,fullen)
  259. char *msg;              /* Complete domain message */
  260. char *eom;
  261. char *compressed;       /* Pointer to compressed name */
  262. char *full;             /* Pointer to result buffer */
  263. int fullen;             /* Length of same */
  264. {
  265.     unsigned int slen;      /* Length of current segment */
  266.     register char *cp;
  267.     int clen = 0;   /* Total length of compressed name */
  268.     int indirect = 0;       /* Set if indirection encountered */
  269.     int nseg = 0;           /* Total number of segments in name */
  270.  
  271.     cp = compressed;
  272.     for(;;){
  273.         slen = uchar(*cp++);    /* Length of this segment */
  274.         if(!indirect)
  275.             clen++;
  276.         if((slen & 0xc0) == 0xc0){
  277.             if(!indirect)
  278.                 clen++;
  279.             indirect = 1;
  280.             /* Follow indirection */
  281.             cp = &msg[((slen & 0x3f)<<8) + uchar(*cp)];
  282.             slen = uchar(*cp++);
  283.         }
  284.         if(slen == 0)   /* zero length == all done */
  285.             break;
  286.         fullen -= slen + 1;
  287.         if(fullen < 0)
  288.             return -1;
  289.         if(!indirect)
  290.             clen += slen;
  291.         while(slen-- != 0)
  292.             *full++ = *cp++;
  293.         *full++ = '.';
  294.         nseg++;
  295.     }
  296.     if(nseg == 0){
  297.         /* Root name; represent as single dot */
  298.         *full++ = '.';
  299.         fullen--;
  300.     }
  301.     *full++ = '\0';
  302.     fullen--;
  303.     return clen;    /* Length of compressed message */
  304. }
  305.  
  306.  
  307.  
  308. #ifdef DSERVER
  309.  
  310. /* Most of this code is based on the DNS server in PA0GRI's 910828
  311.  * Ported to the current NOS code by Johan. K. Reinalda, WG7J
  312.  * for version and bug/feature info, see domain.c
  313.  */
  314.  
  315. static char *
  316. dn_compress(cp,name)
  317. char *cp, *name;
  318. {
  319.     int len,dlen;
  320.     char *cp1;
  321.     dlen = strlen(name);
  322.     for(;;){
  323.         /* Look for next dot */
  324.         cp1 = strchr(name,'.');
  325.         if(cp1 != NULLCHAR)
  326.             len = cp1-name; /* More to come */
  327.         else
  328.             len = dlen;     /* Last component */
  329.         *cp++ = len;            /* Write length of component */
  330.         if(len == 0)
  331.             return cp;
  332.         /* Copy component up to (but not including) dot */
  333.         strncpy(cp,name,(size_t)len);
  334.         cp += len;
  335.         if(cp1 == NULLCHAR){
  336.             *cp++ = 0;      /* Last one; write null and finish */
  337.             return cp;
  338.         }
  339.         name += len+1;
  340.         dlen -= len+1;
  341.     }
  342. }
  343.  
  344. /* Translate a resource record from host format to network format */
  345. static char *
  346. htonrr(rr,buffer)
  347. struct rr *rr;
  348. char *buffer;
  349. {
  350.     struct rr *rrp;
  351.     char *cp, *p;
  352.     int i, len;
  353.  
  354.     cp = buffer;
  355.     for(rrp = rr; rrp != NULLRR; rrp = rrp->next) {
  356. #ifdef notdef
  357.     i = strlen(rrp->name);
  358.     if(rrp->name[i-1] != '.'
  359.        && rrp->origin != NULLCHAR) {
  360.         p = mallocw(i + strlen(rrp->origin) + 2);
  361.         sprintf(p,"%s.%s",rrp->name,rrp->origin);
  362.         cp = dn_compress(cp,p);
  363.         free(p);
  364.     } else
  365. #endif
  366.         cp = dn_compress(cp,rrp->name);
  367.     cp = put16(cp,rrp->type);
  368.     cp = put16(cp,rrp->class);
  369.     cp = put32(cp,rrp->ttl);
  370. #ifdef notdef
  371.     /* The length doesn't seem to be right for all types ! */
  372.     cp = put16(cp,rrp->rdlength);
  373. #endif
  374.     p = cp;     /* This is where the length goes ! */
  375.     cp += 2;    /* Save the space for lenght field */
  376.  
  377.     switch(rrp->type) {
  378.     case TYPE_A:
  379.         cp = put32(cp,rrp->rdata.addr);
  380.         break;
  381.     case TYPE_SOA:
  382.         cp = dn_compress(cp,rrp->rdata.soa.mname);
  383.         cp = dn_compress(cp,rrp->rdata.soa.rname);
  384.         cp = put32(cp,rrp->rdata.soa.serial);
  385.         cp = put32(cp,rrp->rdata.soa.refresh);
  386.         cp = put32(cp,rrp->rdata.soa.retry);
  387.         cp = put32(cp,rrp->rdata.soa.expire);
  388.         cp = put32(cp,rrp->rdata.soa.minimum);
  389.         break;
  390.     case TYPE_HINFO:
  391.         *cp++ = len = strlen(rrp->rdata.hinfo.cpu); 
  392.         strncpy(cp,rrp->rdata.hinfo.cpu,(size_t)len); 
  393.         cp += len;
  394.         *cp++ = len = strlen(rrp->rdata.hinfo.os);
  395.         strncpy(cp,rrp->rdata.hinfo.os,(size_t)len); 
  396.         cp += len;
  397.         break;
  398.     case TYPE_MX:
  399.         cp = put16(cp,rrp->rdata.mx.pref); 
  400.         cp = dn_compress(cp,rrp->rdata.mx.exch);
  401.         break;
  402.     case TYPE_CNAME:
  403.     case TYPE_MB:
  404.     case TYPE_MG:
  405.     case TYPE_MR:
  406.     case TYPE_NS:
  407.     case TYPE_PTR:
  408.         cp = dn_compress(cp,rrp->rdata.data);
  409.         break;
  410.     case TYPE_MINFO:    /* Unsupported type */
  411.     cp = dn_compress(cp,rrp->rdata.minfo.rmailbx);
  412.     cp = dn_compress(cp,rrp->rdata.minfo.emailbx);
  413.     case TYPE_MD:       /* Unsupported type */
  414.     case TYPE_MF:       /* Unsupported type */
  415.     case TYPE_NULL:     /* Unsupported type */
  416.     case TYPE_WKS:      /* Unsupported type */
  417.         cp = dn_compress(cp,rrp->rdata.data);
  418.         break;
  419.     case TYPE_TXT:
  420.     default:
  421.         cp = put16(cp,rrp->rdlength);
  422.         for(i=0 ; i < rrp->rdlength ; i++)
  423.         *cp++ = rrp->rdata.data[i];
  424.         break;
  425.     }
  426.     /* Calculate the lenght of the RR */
  427.     len = cp - p - 2;
  428.     put16(p,len);       /* and set it */
  429.     }
  430.     return cp;
  431. }
  432.  
  433. int
  434. htondomain(dhdr,buffer,buflen)
  435. struct dhdr *dhdr;
  436. char *buffer;   /* Area for query */
  437. int16 buflen;   /* Length of same */
  438. {
  439.     char *cp;
  440.     struct rr *rrp;
  441.     int16 parameter;
  442.     int i, count;
  443.  
  444.     cp = buffer;
  445.     cp = put16(cp,dhdr->id);        
  446.     if(dhdr->qr)
  447.         parameter = 0x8000;
  448.     else
  449.         parameter = 0;
  450.     parameter |= (dhdr->opcode & 0x0f) << 11;
  451.     if(dhdr->aa)
  452.         parameter |= DOM_AUTHORITY;
  453.     if(dhdr->tc)
  454.         parameter |= DOM_TRUNC;
  455.     if(dhdr->rd)
  456.         parameter |= DOM_DORECURSE;
  457.     if(dhdr->ra)
  458.         parameter |= DOM_CANRECURSE;
  459.     parameter |= (dhdr->rcode & 0x0f);
  460.     cp = put16(cp,parameter);
  461.     cp = put16(cp,dhdr->qdcount);
  462.     cp = put16(cp,dhdr->ancount);
  463.     cp = put16(cp,dhdr->nscount);
  464.     cp = put16(cp,dhdr->arcount);
  465.     if((count = dhdr->qdcount) > 0) {
  466.     rrp = dhdr->questions;
  467.         for(i = 0; i < count; i++) {
  468.         cp = dn_compress(cp,rrp->name);
  469.         cp = put16(cp,rrp->type);
  470.         cp = put16(cp,rrp->class);
  471.         rrp = rrp->next;
  472.         }
  473.     }
  474.     if((count = dhdr->ancount) > 0) {
  475.     rrp = dhdr->answers;
  476.         for(i = 0; i < count; i++) {
  477.         cp = htonrr(rrp,cp);
  478.         rrp = rrp->next;
  479.         }
  480.     }
  481.     if((count = dhdr->nscount) > 0) {
  482.     rrp = dhdr->authority;
  483.         for(i = 0; i < count; i++) {
  484.         cp = htonrr(rrp,cp);
  485.         rrp = rrp->next;
  486.         }
  487.     }
  488.     if((count = dhdr->arcount) > 0) {
  489.     rrp = dhdr->additional;
  490.     for(i = 0; i < count; i++) {
  491.         cp = htonrr(rrp,cp);
  492.         rrp = rrp->next;
  493.         }
  494.     }
  495.     return cp - buffer;
  496. }
  497.  
  498.  
  499. #endif /* DSERVER */
  500.  
  501.